﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Drawing;
using DevExpress.XtraGrid.Views.Grid;
using ProtocolVN.Framework.Core;
using DevExpress.XtraGrid.Columns;
using DevExpress.XtraGrid;

namespace ProtocolVN.Framework.Win
{
    public interface ISoLgTrLg
    {
        //HH_ID, SO_LUONG, TRONG_LUONG, STT(nếu có)
        DataTable GetSoLgTrLg();
    }

    /// <summary>
    /// DUYVT
    /// Ràng buộc này sử dụng cho các loại phiếu mà 1 hàng hóa phân biệt thông qua ID
    /// </summary>
    public class RangBuocSoLgTrLg : RangBuocRule
    {
        #region RangBuocRule Members
        DataTable ConLai;
        PhieuType Src;
        long SrcID;
        PhieuType Des;
        long DesID;
        object DesObj;
        PLGridView DesGrid;

        public RangBuocSoLgTrLg() { }

        public RangBuocSoLgTrLg(PhieuType Src, long SrcID, PhieuType Des, long DesID, 
            object DesObj, PLGridView DesGrid)
        {
            this.Src = Src;
            this.SrcID = SrcID;
            this.Des = Des;
            this.DesID = DesID;
            this.DesObj = DesObj;
            this.DesGrid = DesGrid;
        }

        //Trả về số lượng, trọng lượng còn lại có thể chấp nhận
        private bool Check(PhieuType Src, long SrcID, List<object[]> LObj, PhieuType Des, 
            long DesID, object DesObj, PLGridView DesGrid)
        {
            ISoLgTrLg data = (ISoLgTrLg)DesObj;
            //Tạo DataTable(HH_ID, SO_LUONG, TRONG_LUONG)
            DataTable dt_lienquan = RangBuocSoLgTrLgHelp.CreateDTHangHoa(LObj, DesID);
            DataTable dt_sum = RangBuocSoLgTrLgHelp.CreateDTHangHoa(Src, SrcID);
        
            //Lấy HH_ID, SO_LUONG, TRONG_LUONG cua DesObj nếu tồn tại
            if (data != null)
            {
                DataTable dt_des = data.GetSoLgTrLg();
                //Merge thêm vào dt_lienquan từ dt_des
                RangBuocSoLgTrLgHelp.MergeAddHangHoa(ref dt_lienquan, dt_des);
            }     
            //Kiểm tra ràng buộc về số lượng và trọng lượng
            //Kết quả trả về DataTable miêu tả các dòng vi phạm
            DataTable dt_vipham = RangBuocSoLgTrLgHelp.KiemTraRangBuoc(dt_sum, dt_lienquan);
            if (dt_vipham.Rows.Count != 0 && DesGrid != null)            
                RangBuocSoLgTrLgHelp.ShowErrorOnGrid(DesGrid, dt_vipham);            

            //Merge giảm vào dt_sum từ dt_lienquan
            RangBuocSoLgTrLgHelp.MergeMinusHangHoa(ref dt_sum, dt_lienquan);
            //Set số lượng còn lại
            ConLai = dt_sum;

            //Nếu dt_vipham không tồn tại dòng vi phạm và phiếu nguồn chưa tạo hết phiếu liên quan
            bool flag = false;            
            if (data != null)
            {
                if (dt_vipham.Rows.Count == 0)
                    flag = true;
            }
            else 
            {
                if (RangBuocSoLgTrLgHelp.KiemTraTaoPhieu(ConLai))
                    flag = true;
            }
            return flag;
        }
        
        public DataTable GetConLai()
        {
            foreach (DataRow dr in ConLai.Rows)
            {
                if (HelpNumber.ParseDecimal(dr["SO_LUONG"]) <= 0 ||
                    HelpNumber.ParseDecimal(dr["TRONG_LUONG"]) <= 0)
                {
                    dr.Delete();
                }
            }
            return ConLai;
        }
        #endregion

        #region RangBuocRule Members

        public List<InvalidInfo> Check()
        {
            List<InvalidInfo> ret = new List<InvalidInfo>();
            List<object[]> LObj = DAPhieuLienQuan.GetListPhieuLienQuan(SrcID, Src, Des);
            bool flag = Check(Src, SrcID, LObj, Des, DesID, DesObj, DesGrid);
            if (flag == false)
            {
                ret.Add(new InvalidInfo(
                    "Vi phạm ràng buộc số lượng, trọng lượng", 
                    "Vui lòng kiểm tra lại các thông tin liên quan số lượng và trọng lượng", 
                    InvalidInfo.InvalidType.ERROR));
            }
            return ret;
        }

        #endregion

        public static bool Check(RangBuocSoLgTrLg rule, PhieuType Src, long SrcID, 
            PhieuType Des, long DesID, Object DesObj, PLGridView DesGrid)
        {
            //Lay danh sach cac phieu thuoc nhom phieu des duoc tao tu (Src, SrcID)
            //Duoc xay dung tu PhieuLienQuan List (TYPE_ID, ID)            
            List<object[]> LObj = DAPhieuLienQuan.GetListPhieuLienQuan(SrcID, Src, Des);
            return rule.Check(Src, SrcID, LObj, Des, DesID, DesObj, DesGrid);
        }
        //VULA: Merge thêm cột ghi chú
        public static DataSet GetGhiChu(DataSet _DataSetNguon, DataSet DataSetConLai)
        {
            DataSetConLai.Tables[0].Columns.Add("GHI_CHU");
            if (DataSetConLai != null && _DataSetNguon != null)
            {
                foreach (DataRow dr in DataSetConLai.Tables[0].Rows)
                {
                    if (dr.RowState == DataRowState.Deleted) continue;
                    foreach (DataRow drPN in _DataSetNguon.Tables[0].Rows)
                    {
                        if (dr["HH_ID"].ToString().Equals(drPN["HH_ID"].ToString()))
                        {
                            dr["GHI_CHU"] = drPN["GHI_CHU"];
                            break;
                        }
                    }
                }
            }
            return DataSetConLai;
        }
    }
    
    public class RangBuocSoLgTrLgHelp
    {
        /// <summary>
        /// Tạo DataTable(HH_ID, SO_LUONG, TRONG_LUONG) lưu trữ hàng hóa, kèm số lượng, trọng lượng
        /// Thuộc 1 phiếu bất kì có loại phiếu và ID
        /// </summary>
        /// <param name="type">Loại phiếu</param>
        /// <param name="id">ID</param>
        /// <returns></returns>
        public static DataTable CreateDTHangHoa(PhieuType type, long id)
        {
           return  CreateDTHangHoa(type, id, "_CT");
        }
        public static DataTable CreateDTHangHoa(PhieuType type, long id,string TenBangCT)//TenBangCT=CT
        {
            try
            {
                string sql = "select hh_id as \"HH_ID\", "
                    + type.GetSOLGField() + " as \"SO_LUONG\","
                    + type.GetTRLGField() + " as \"TRONG_LUONG\" from "
                    + type.GetTableName() + TenBangCT + " where 1=1";
                DataSet dsTest = new DataSet();
                DatabaseFB.LoadDataSet(dsTest, type.GetTableName() + TenBangCT, type.GetIDField(), -1);
                if (dsTest != null && dsTest.Tables.Count > 0 && dsTest.Tables[0].Columns.Contains("TTHTK_ID"))
                {
                    sql = "select hh_id as \"HH_ID\", "
                    + type.GetSOLGField() + " as \"SO_LUONG\","
                    + type.GetTRLGField() + " as \"TRONG_LUONG\", TTHTK_ID as \"TTHTK_ID\" from "
                    + type.GetTableName() + TenBangCT + " where 1=1";
                }
                QueryBuilder filter = new QueryBuilder(sql);
                filter.addID(type.GetIDField(), id);
                DataSet ds = DABase.getDatabase().LoadDataSet(filter);
                return ds.Tables[0];
            }
            catch (Exception ex)
            {
                PLException.AddException(ex);
                return null;
            }
        }
        
        /// <summary>
        /// Tạo DataTable(HH_ID, SO_LUONG, TRONG_LUONG) lưu trữ hàng hóa, kèm số lượng, trọng lượng
        /// Sử dụng trong việc kiểm tra ràng buộc về số lượng và trọng lượng
        /// </summary>
        /// <param name="LObj">Danh sách phiếu liên quan (Loại phiếu, ID)</param>
        /// <returns>DataTable(HH_ID, SO_LUONG, TRONG_LUONG)</returns>
        public static DataTable CreateDTHangHoa(List<object[]> LObj, long DesID)
        {
            DataTable dt_rough = new DataTable();
            DataColumn[] dc_arr = new DataColumn[] { new DataColumn("HH_ID"),
                new DataColumn("SO_LUONG"),
                new DataColumn("TRONG_LUONG") };
            dt_rough.Columns.AddRange(dc_arr);

            dt_rough.Columns["SO_LUONG"].DataType = Type.GetType("System.Decimal");
            dt_rough.Columns["TRONG_LUONG"].DataType = Type.GetType("System.Decimal");

            try
            {
                foreach (object[] obj_arr in LObj)
                {
                    PhieuType PLQ_type = (PhieuType)obj_arr[0];
                    long PLQ_id = (long)obj_arr[1];
                    if (DesID == -1 || (DesID != -1 && DesID != PLQ_id))
                    {
                        QueryBuilder filter = new QueryBuilder("select hh_id as \"HH_ID\", "
                            + PLQ_type.GetSOLGField() + " as \"SO_LUONG\"," + PLQ_type.GetTRLGField()
                            + " as \"TRONG_LUONG\" from " + PLQ_type.GetTableName()
                            + "_CT" + " where 1=1");
                        filter.addID(PLQ_type.GetIDField(), PLQ_id);
                        DataSet ds = DABase.getDatabase().LoadDataSet(filter);
                        DataRow[] dr_arr = ds.Tables[0].Select();
                        foreach (DataRow dr in dr_arr)
                            dt_rough.ImportRow(dr);
                    }
                }

                DataTable dt_last = dt_rough.Clone();
                DataTable dt_distinct = SelectDistinct(dt_rough, "HH_ID");
                foreach (DataRow dr in dt_distinct.Rows)
                {
                    DataRow _dr = dt_last.NewRow();
                    _dr["HH_ID"] = dr["HH_ID"];
                    _dr["SO_LUONG"] = dt_rough.Compute("Sum(SO_LUONG)", "HH_ID='" + dr["HH_ID"] + "'");
                    _dr["TRONG_LUONG"] = dt_rough.Compute("Sum(TRONG_LUONG)", "HH_ID='" + dr["HH_ID"] + "'");
                    dt_last.Rows.Add(_dr);
                }
                return dt_last;
            }
            catch (Exception ex)
            {
                PLException.AddException(ex);
                return null;
            }
        }
        /// <summary>
        /// Hàm chọn trường distinct trên DataTable
        /// </summary>
        /// <param name="SourceTable">DataTable nguồn</param>
        /// <param name="FieldNames">Danh sách các trường cần chọn distinct</param>
        /// <returns></returns>
        public static DataTable SelectDistinct(DataTable SourceTable, params string[] FieldNames)
        {
            object[] lastValues;
            DataTable newTable;
            DataRow[] orderedRows;

            if (FieldNames == null || FieldNames.Length == 0)
                throw new ArgumentNullException("FieldNames");

            lastValues = new object[FieldNames.Length];
            newTable = new DataTable();

            foreach (string fieldName in FieldNames)
                newTable.Columns.Add(fieldName, SourceTable.Columns[fieldName].DataType);

            orderedRows = SourceTable.Select("", string.Join(", ", FieldNames));

            foreach (DataRow row in orderedRows)
            {
                if (!fieldValuesAreEqual(lastValues, row, FieldNames))
                {
                    newTable.Rows.Add(createRowClone(row, newTable.NewRow(), FieldNames));

                    setLastValues(lastValues, row, FieldNames);
                }
            }

            return newTable;
        }

        /// <summary>
        /// Hàm hổ trợ cho SelectDistinct
        /// </summary>
        /// <param name="lastValues"></param>
        /// <param name="currentRow"></param>
        /// <param name="fieldNames"></param>
        /// <returns></returns>
        private static bool fieldValuesAreEqual(object[] lastValues, DataRow currentRow, string[] fieldNames)
        {
            bool areEqual = true;

            for (int i = 0; i < fieldNames.Length; i++)
            {
                if (lastValues[i] == null || !lastValues[i].Equals(currentRow[fieldNames[i]]))
                {
                    areEqual = false;
                    break;
                }
            }

            return areEqual;
        }

        /// <summary>
        /// Hàm hổ trợ cho SelectDistinct
        /// </summary>
        /// <param name="sourceRow"></param>
        /// <param name="newRow"></param>
        /// <param name="fieldNames"></param>
        /// <returns></returns>
        private static DataRow createRowClone(DataRow sourceRow, DataRow newRow, string[] fieldNames)
        {
            foreach (string field in fieldNames)
                newRow[field] = sourceRow[field];

            return newRow;
        }

        /// <summary>
        /// Hàm hổ trợ cho SelectDistinct
        /// </summary>
        /// <param name="lastValues"></param>
        /// <param name="sourceRow"></param>
        /// <param name="fieldNames"></param>
        private static void setLastValues(object[] lastValues, DataRow sourceRow, string[] fieldNames)
        {
            for (int i = 0; i < fieldNames.Length; i++)
                lastValues[i] = sourceRow[fieldNames[i]];
        }

        /// <summary>
        /// Kiểm tra ràng buộc số lượng, trọng lương dựa vào DataTable hàng hóa còn lại
        /// </summary>
        /// <param name="dt_remain">DataTable hàng hóa còn lại</param>
        /// <returns>Được tạo phiếu hay không</returns>
        public static bool KiemTraTaoPhieu(DataTable dt_remain)
        {
            if (dt_remain == null || dt_remain.Rows.Count == 0)
                return false;

            try
            {
                bool flag = false;
                foreach (DataRow dr in dt_remain.Rows)
                {
                    if (HelpNumber.ParseDecimal(dr["SO_LUONG"]) > 0 && 
                        HelpNumber.ParseDecimal(dr["TRONG_LUONG"]) > 0)
                    {
                        flag = true;
                        break;
                    }
                }
                return flag;
            }
            catch (Exception ex)
            {
                PLException.AddException(ex);
                return false;
            }
        }

        /// <summary>
        /// Merge thêm số lượng, trọng lượng vào dt_main từ dt_add 
        /// </summary>
        /// <param name="dt_main">DataTable cần merge</param>
        /// <param name="dt_add">DataTable thêm</param>            
        public static void MergeAddHangHoa(ref DataTable dt_main, DataTable dt_add)
        {            
            if (!CheckColumnsExist(dt_main, "HH_ID", "SO_LUONG", "TRONG_LUONG") ||
                !CheckColumnsExist(dt_add, "HH_ID", "SO_LUONG", "TRONG_LUONG"))
            {
                return;          
            }

            List<int> list_temp = new List<int>();
            dt_main.Columns.Add("SO_LUONG_DICH_DA_CO", Type.GetType("System.Decimal"));
            dt_main.Columns.Add("TRONG_LUONG_DICH_DA_CO", Type.GetType("System.Decimal"));
            foreach (DataRow dr in dt_add.Rows)
            {
                if (dr.RowState != DataRowState.Deleted)
                {
                    int i = CheckHangHoaExist(dt_main, HelpNumber.ParseInt64(dr["HH_ID"]));                    
                    if (i != -1)
                    {
                        if (!list_temp.Contains(i))
                        {
                            if (dt_main.Rows[i]["SO_LUONG_DICH_DA_CO"].ToString() == string.Empty && 
                                dt_main.Rows[i]["TRONG_LUONG_DICH_DA_CO"].ToString() == string.Empty)
                            {
                                dt_main.Rows[i]["SO_LUONG_DICH_DA_CO"] = dt_main.Rows[i]["SO_LUONG"];
                                dt_main.Rows[i]["TRONG_LUONG_DICH_DA_CO"] = dt_main.Rows[i]["TRONG_LUONG"];
                                list_temp.Add(i);
                            }
                        }
                        dt_main.Rows[i]["SO_LUONG"] = HelpNumber.ParseDecimal(dt_main.Rows[i]["SO_LUONG"])
                            + HelpNumber.ParseDecimal(dr["SO_LUONG"]);
                        dt_main.Rows[i]["TRONG_LUONG"] = HelpNumber.ParseDecimal(dt_main.Rows[i]["TRONG_LUONG"])
                            + HelpNumber.ParseDecimal(dr["TRONG_LUONG"]);                        
                    }
                    else
                    {
                        DataRow _dr = dt_main.NewRow();
                        _dr["HH_ID"] = dr["HH_ID"];
                        _dr["SO_LUONG"] = dr["SO_LUONG"];
                        _dr["TRONG_LUONG"] = dr["TRONG_LUONG"];
                        _dr["SO_LUONG_DICH_DA_CO"] = 0;
                        _dr["TRONG_LUONG_DICH_DA_CO"] = 0;
                        dt_main.Rows.Add(_dr);
                    }
                }
            }
        }

        /// <summary>
        /// Merge giảm số lượng, trọng lượng vào dt_main từ dt_minus
        /// </summary>
        /// <param name="dt_main">DataTable cần merge</param>
        /// <param name="dt_add">DataTable giảm</param>
        public static void MergeMinusHangHoa(ref DataTable dt_main, DataTable dt_minus)
        {
            if (!CheckColumnsExist(dt_main, "HH_ID", "SO_LUONG", "TRONG_LUONG") ||
                !CheckColumnsExist(dt_minus, "HH_ID", "SO_LUONG", "TRONG_LUONG"))
                return;

            foreach (DataRow dr in dt_minus.Rows)
            {
                int i = CheckHangHoaExist(dt_main, HelpNumber.ParseInt64(dr["HH_ID"]));
                if (i != -1)
                {
                    dt_main.Rows[i]["SO_LUONG"] = HelpNumber.ParseDecimal(dt_main.Rows[i]["SO_LUONG"])
                        - HelpNumber.ParseDecimal(dr["SO_LUONG"]);
                    dt_main.Rows[i]["TRONG_LUONG"] = HelpNumber.ParseDecimal(dt_main.Rows[i]["TRONG_LUONG"])
                        - HelpNumber.ParseDecimal(dr["TRONG_LUONG"]);
                }
            }
        }

        /// <summary>
        /// Kiểm tra ràng buộc về số lượng, trọng lượng
        /// </summary>
        /// <param name="dt_nguon">DataTable nguồn</param>
        /// <param name="dt_dich">DataTable đích</param>
        /// <returns>DataTable miêu tả các dòng không hợp lệ</returns>
        public static DataTable KiemTraRangBuoc(DataTable dt_nguon, DataTable dt_dich)
        {
            DataTable dtViPham = new DataTable();            
            dtViPham.Columns.Add("HH_ID", Type.GetType("System.Int64"));
            dtViPham.Columns.Add("VI_PHAM");
            
            if (dt_nguon == null || dt_nguon.Rows.Count == 0 || dt_dich == null)
                return dtViPham;

            foreach (DataRow dr_dich in dt_dich.Rows)
            {
                bool exists = false;
                DataRow rowViPham = dtViPham.NewRow();
                foreach (DataRow dr_nguon in dt_nguon.Rows)
                {                    
                    if (HelpNumber.ParseInt64(dr_dich["HH_ID"]) == HelpNumber.ParseInt64(dr_nguon["HH_ID"]))
                    {
                        //HH_ID có tồn tại trong phiếu nguồn
                        exists = true;
                        decimal soLuongDich = HelpNumber.ParseDecimal(dr_dich["SO_LUONG"]);
                        decimal soLuongNguon = HelpNumber.ParseDecimal(dr_nguon["SO_LUONG"]);
                        decimal trongLuongDich = HelpNumber.ParseDecimal(dr_dich["TRONG_LUONG"]);
                        decimal trongLuongNguon = HelpNumber.ParseDecimal(dr_nguon["TRONG_LUONG"]);
                        decimal soLuongDichDaCo = 0;
                        decimal trongLuongDichDaCo = 0;

                        if (dt_dich.Columns.Contains("SO_LUONG_DICH_DA_CO") &&
                            dt_dich.Columns.Contains("TRONG_LUONG_DICH_DA_CO"))
                        {
                            soLuongDichDaCo = HelpNumber.ParseDecimal(dr_dich["SO_LUONG_DICH_DA_CO"]);
                            trongLuongDichDaCo = HelpNumber.ParseDecimal(dr_dich["TRONG_LUONG_DICH_DA_CO"]);
                        }
                        if ((soLuongDich > soLuongNguon) || (trongLuongDich > trongLuongNguon))
                        {
                            string viPham = "";
                            rowViPham["HH_ID"] = dr_dich["HH_ID"];
                            if (soLuongDich > soLuongNguon)
                            {
                                viPham = "Vi phạm ràng buộc về số lượng. Số lượng cho phép: <=" +
                                    (soLuongNguon - soLuongDichDaCo) + " !";
                            }
                            if (trongLuongDich > trongLuongNguon)
                            {
                                viPham = "Vi phạm ràng buộc về trọng lượng. Trọng lượng cho phép: <=" +
                                    (trongLuongNguon - trongLuongDichDaCo) + " !";
                            }
                            if ((soLuongDich > soLuongNguon) && (trongLuongDich > trongLuongNguon))
                            {
                                viPham = "Vi phạm ràng buộc về số lượng và trọng lượng. SLg cho phép:<=" +
                                    (soLuongNguon - soLuongDichDaCo) + "; TrLg cho phép: <=" +
                                    (trongLuongNguon - trongLuongDichDaCo) + " !";
                            }
                            rowViPham["VI_PHAM"] = viPham;
                            if (RangBuocSoLgTrLgHelp.CheckHangHoaExist(dtViPham,
                                HelpNumber.ParseInt64(rowViPham["HH_ID"])) == -1)
                            {
                                dtViPham.Rows.Add(rowViPham);
                            }
                        }
                    }
                }
                if (!exists)
                {
                    rowViPham["HH_ID"] = dr_dich["HH_ID"];
                    rowViPham["VI_PHAM"] = "Hàng hóa này không có trong phiếu nguồn";                    
                    dtViPham.Rows.Add(rowViPham);
                }
            }
            return dtViPham;
        }

        /// <summary>
        /// Thể hiện lỗi trên Grid dựa vào DataTable chứa các dòng lỗi        
        /// </summary>
        /// <param name="gridDich">Grid cần thể hiện lỗi</param>
        /// <param name="dt_error">DataTable các dòng lỗi</param>
        public static void ShowErrorOnGrid(PLGridView gridDich, DataTable dt_error)
        {
            AddFormatCond(gridDich);            
            for (int i = 0; i < gridDich.RowCount; i++)
            {
                gridDich.SetRowCellValue(i, gridDich.Columns["CHECK"], 1);
                gridDich.SetRowCellValue(i, gridDich.Columns["VI_PHAM"], "");
                foreach (DataRow dr_error in dt_error.Rows)
                {
                    DataRow rowDich = gridDich.GetDataRow(i);
                    if (HelpNumber.ParseInt64(rowDich["HH_ID"]) == HelpNumber.ParseInt64(dr_error["HH_ID"]))
                    {
                        gridDich.SetRowCellValue(i, gridDich.Columns["CHECK"], 0);
                        gridDich.SetRowCellValue(i, gridDich.Columns["VI_PHAM"], dr_error["VI_PHAM"]);
                        gridDich.UpdateCurrentRow();
                        gridDich.OptionsView.ShowPreview = true;
                        gridDich.OptionsView.AutoCalcPreviewLineCount = true;                        
                        gridDich.PreviewFieldName = "VI_PHAM";
                        gridDich.CustomDrawRowPreview += 
                            new DevExpress.XtraGrid.Views.Base.RowObjectCustomDrawEventHandler(
                                gridDich_CustomDrawRowPreview);                                                
                    }
                }
            }
        }

        /// <summary>
        /// Customize lại phần review của dòng trong PLGridView
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public static void gridDich_CustomDrawRowPreview(object sender, DevExpress.XtraGrid.Views.Base.RowObjectCustomDrawEventArgs e)
        {
            e.Appearance.ForeColor = Color.Red;
            e.Appearance.TextOptions.HAlignment = DevExpress.Utils.HorzAlignment.Far;
            e.Appearance.Font = new Font("Tahoma", 8.25F, FontStyle.Italic);
        }  

        /// <summary>
        /// Khởi tạo định dạng lỗi trên Grid 
        /// </summary>
        /// <param name="grid">Grid cần khởi tạo định dạng lỗi</param>
        public static void AddFormatCond(PLGridView grid)
        {
            DataSet ds = ((DataTable)grid.GridControl.DataSource).DataSet;

            //Khởi tạo cột Check
            GridColumn colCheck = new GridColumn();
            colCheck.FieldName = "CHECK";
            colCheck.Visible = false;            
            if (!ds.Tables[0].Columns.Contains("CHECK"))
                ds.Tables[0].Columns.Add("CHECK");
            if (!grid.Columns.Contains(colCheck))
                grid.Columns.Add(colCheck);

            //Khởi tạo cột thông báo vi phạm
            GridColumn colVipham = new GridColumn();
            colVipham.FieldName = "VI_PHAM";
            colVipham.Visible = false;
            if (!ds.Tables[0].Columns.Contains("VI_PHAM"))
                ds.Tables[0].Columns.Add("VI_PHAM");
            if (!grid.Columns.Contains(colVipham))
                grid.Columns.Add(colVipham);

            StyleFormatCondition styleFormatCond = new StyleFormatCondition();
            styleFormatCond.Appearance.BackColor = System.Drawing.Color.Red;
            styleFormatCond.Appearance.Options.UseBackColor = true;            
            styleFormatCond.ApplyToRow = true;
            styleFormatCond.Column = colCheck;
            styleFormatCond.Condition = DevExpress.XtraGrid.FormatConditionEnum.Equal;
            styleFormatCond.Value1 = 0;
            grid.FormatConditions.AddRange(new StyleFormatCondition[] { styleFormatCond });
        }

        /// <summary>
        /// Hàm hổ trợ cho MergeAddHangHoa
        /// </summary>
        /// <param name="dt">DataTable</param>
        /// <param name="id">ID hàng hóa</param>
        /// <returns>Vị trí hàng hóa trong DataTable</returns>
        public static int CheckHangHoaExist(DataTable dt, long hh_id)
        {
            if (dt == null)
                return -1;

            try
            {
                for (int i = 0; i < dt.Rows.Count; i++)
                {
                    DataRow dr = dt.Rows[i];
                    if (HelpNumber.ParseInt64(dr["HH_ID"]).Equals(hh_id))
                        return i;
                }
                return -1;
            }
            catch (Exception ex)
            {
                PLException.AddException(ex);
                return -1;
            }
        }

        /// <summary>
        /// Kiểm tra DataTable có tồn tại các cột chỉ định hay không
        /// </summary>
        /// <param name="dt">DataTable kiểm tra</param>
        /// <param name="column_fields">Danh sách các cột chỉ định</param>
        /// <returns></returns>
        public static bool CheckColumnsExist(DataTable dt, params string[] column_fields)
        {
            bool flag = true;
            if (dt == null)
                return false;

            foreach (string field in column_fields)
            {
                if (!dt.Columns.Contains(field))
                {
                    flag = false;
                    break;
                }
            }
            return flag;
        }
    }
}
